#pragma once

#include "Comm.hpp"
#include "Util.hpp"
#include "HttpRequest.hpp"
#include "HttpResponse.hpp"
#include "HttpContext.hpp"

class HttpServer
{
private:
    using Handler = std::function<void(const HttpRequest &, HttpResponse *)>;

    void ErrorHandler(const HttpRequest &requ, HttpResponse *resp)
    {
        // 组织一个错误展示页面
        std::string body;
        body += "<html><head><meta http-equiv='Content-Type' content='text/html;charset=utf-8'></head>";
        body += "<body><h1>";
        body += std::to_string(resp->GetStatu());
        body += " ";
        body += Util::GetStatuDesc(resp->GetStatu());
        body += "</h1></body></html>";
        // 将页面数据当作响应正文放进 resp 中
        resp->SetContent(body);
    }

    // 响应的组织和发送
    void WriteResponse(const PtrConnection &conn, const HttpRequest &requ, HttpResponse &resp)
    {
        // 完善头部字段
        if (requ.HandleClose() == true)
        {
            resp.SetHeader("Connection", "close");
        }
        else
        {
            resp.SetHeader("Connection", "keep-alive");
        }

        if (resp.GetBodySize() != 0)
        {
            if (resp.HasHeader("Content-Length") == false)
                resp.SetHeader("Content-Length", std::to_string(resp.GetBodySize()));
            if (resp.HasHeader("Content-Type") == false)
                resp.SetHeader("Content-Type", "application/octet-stream");
        }

        if (resp._redirect_flag == true)
        {
            resp.SetHeader("Location", resp._redirect_url);
        }

        // 将 resp 中的要素，按照 HTTP 协议格式进行组织
        std::stringstream resp_str;
        resp_str << requ._version << " " << std::to_string(resp._statu) << " " + Util::GetStatuDesc(resp._statu) << "\r\n";
        for (auto &head : resp._headers)
        {
            resp_str << head.first << ": " << head.second << "\r\n";
        }
        resp_str << "\r\n";
        resp_str << resp._body;

        // 发送数据
        conn->Send(resp_str.str().c_str(), resp_str.str().size());
    }

    bool IsFileHandler(const HttpRequest &requ)
    {
        // 必须设置了静态资源根目录
        if (_base_dir.empty())
        {
            LOG(WARNING, "The static resource root directory is not set!\n");
            return false;
        }
        // 请求方法必须是 GET 或者 HEAD
        if (requ._method != "GET" && requ._method != "HEAD")
        {
            // LOG(WARNING, "Illegal request method!\n");
            return false;
        }
        // 请求的资源路径必须合法
        if (Util::IsValidPath(requ._path) == false)
        {
            LOG(WARNING, "Invalid request path!\n");
            return false;
        }
        // 请求的资源必须存在
        std::string requ_path = _base_dir + requ._path;
        if (requ._path.back() == '/')
        {
            requ_path += "index.html";
        }
        if (Util::IsRegular(requ_path) == false)
        {
            return false;
        }
        return true;
    }

    // 静态资源的请求
    bool FileHandler(const HttpRequest &requ, HttpResponse *resp)
    {
        std::string requ_path = _base_dir + requ._path;
        if (requ._path.back() == '/')
        {
            requ_path += "index.html";
        }

        bool ret = Util::ReadFile(requ_path, &(resp->_body));
        if (ret == false)
            return false;

        std::string mime = Util::GetExtMime(requ_path);
        resp->SetHeader("Content-Type", mime);
        return true;
    }

    // 功能性请求的分类处理
    void Dispatcher(HttpRequest &requ, HttpResponse *resp, std::vector<std::pair<std::regex, Handler>> &route)
    {
        for (auto &handle : route)
        {
            const std::regex &re = handle.first;
            const Handler &func = handle.second;
            bool ret = std::regex_match(requ._path, requ._matches, re);
            if (ret == false)
            {
                continue;
            }
            return func(requ, resp);
        }
        resp->_statu = 404;
    }

    // 路由功能性请求处理函数
    void Route(HttpRequest &requ, HttpResponse *resp)
    {
        // 对请求进行分辨，是一个静态资源请求，还是一个功能性请求
        // GET POST 都先默认为静态资源请求
        if (IsFileHandler(requ) == true)
        {
            FileHandler(requ, resp);
            return;
        }

        if (requ._method == "GET" || requ._method == "HEAD")
            return Dispatcher(requ, resp, _GET_route);
        else if (requ._method == "POST")
            return Dispatcher(requ, resp, _POST_route);
        else if (requ._method == "PUT")
            return Dispatcher(requ, resp, _PUT_route);
        else if (requ._method == "DELETE")
            return Dispatcher(requ, resp, _DELETE_route);

        resp->_statu = 405;
    }

    // 设置上下文
    void OnConnected(const PtrConnection &conn)
    {
        conn->SetContext(HttpContext());
        LOG(HDEBUG, "NEW CONNECTION %d -> %p\n", conn->GetFD(), conn.get());
    }

    void OnClosed(const PtrConnection &conn)
    {
        LOG(HDEBUG, "RELEASE CONNECTION %d -> %p\n", conn->GetFD(), conn.get());
    }

    std::string RequestStr(const HttpRequest &requ)
    {
        std::stringstream ss;
        ss << requ._method << " " << requ._path << " " << requ._version << "\r\n";
        for (auto &head : requ._headers)
        {
            ss << head.first << ": " << head.second << "\r\n";
        }
        // for (auto &param : requ._params)
        // {
        //     ss << param.first << ": " << param.second << "\r\n";
        // }
        ss << "\r\n";
        ss << requ._body;
        return ss.str();
    }

    // 缓冲区数据进行解析和处理
    void OnMessage(const PtrConnection &conn, Buffer *buf)
    {
        // LOG(INFO, "buf->GetSizeOfReadableData() = %d\n", buf->GetSizeOfReadableData());
        while (buf->GetSizeOfReadableData() > 0)
        {
            // 获取上下文
            HttpContext *context = conn->GetContext()->getValPtr<HttpContext>();
            // LOG(INFO, "buf->GetSizeOfReadableData() = %d\n", buf->GetSizeOfReadableData());
            // 通过上下文对缓冲区数据进行解析，得到 HttpRequest 对象
            context->RecvHttpRequ(buf);
            LOG(HDEBUG, "一条请求从 buf 中接收完毕！\n");
            HttpRequest &requ = context->GetRequ();
            // LOG(INFO, "RecvHttpRequ: %s\n", RequestStr(requ).c_str());
            // 请求路由 + 业务处理
            HttpResponse resp(context->GetRespStatu());
            // LOG(INFO, "context->GetRespStatu(): %d\n", context->GetRespStatu());
            if (context->GetRespStatu() >= 400)
            {
                LOG(HDEBUG, "请求解析错误！状态码：%d\n", context->GetRespStatu());
                ErrorHandler(requ, &resp);       // 填充一个错误显示页面
                WriteResponse(conn, requ, resp); // 组织响应给客户端
                context->Reset();
                buf->MoveReadBackward(buf->GetSizeOfReadableData());
                conn->Shutdown();
                return;
            }
            if (context->GetRecvStatu() != RECV_HTTP_OVER)
            {
                LOG(HDEBUG, "请求未接收完整！\n");
                return;
            }
            Route(requ, &resp);
            LOG(HDEBUG, "已完成路由，填充响应！\n");
            // 对 HttpResponse 进行组织发送
            WriteResponse(conn, requ, resp);
            LOG(HDEBUG, "HttpResponse 已组织发送！\n");
            // LOG(INFO, "RecvHttpRequ: %s\n", RequestStr(requ).c_str());
            // 重置上下文
            context->Reset();
            // 根据长短连接判断是否关闭连接或者接续处理
            // LOG(INFO, "requ.HandleClose() = %d\n", requ.HandleClose());
            // LOG(INFO, "RecvHttpRequ: %s\n", RequestStr(requ).c_str());
            if (resp.HandleClose() == true)
            {
                LOG(HDEBUG, "短连接销毁！\n");
                conn->Shutdown();
            }
            LOG(HDEBUG, "长连接继续处理！剩余： %d\n", buf->GetSizeOfReadableData());
        }
    }

public:
    HttpServer(in_port_t port, int timeout = 10)
        : _server(port)
    {
        _server.EnableInactiveRelease(timeout);
        _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected, this, std::placeholders::_1));
        _server.SetClosedCallback(std::bind(&HttpServer::OnClosed, this, std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
    }

    void SetBaseDir(const std::string &path)
    {
        assert(Util::IsDirectory(path) == true);
        _base_dir = path;
    }

    void GET(const std::string &pattern, const Handler &handler) { _GET_route.push_back({std::regex(pattern), handler}); }

    void POST(const std::string &pattern, const Handler &handler) { _POST_route.push_back({std::regex(pattern), handler}); }

    void PUT(const std::string &pattern, const Handler &handler) { _PUT_route.push_back({std::regex(pattern), handler}); }

    void DELETE(const std::string &pattern, const Handler &handler) { _DELETE_route.push_back({std::regex(pattern), handler}); }

    void SetThreadCount(int count) { _server.SetThreadCount(count); }

    void Listen() { _server.Start(); }

private:
    std::string _base_dir; // 静态资源根目录
    TcpServer _server;     // muduo 通信组件
    std::vector<std::pair<std::regex, Handler>> _GET_route;
    std::vector<std::pair<std::regex, Handler>> _POST_route;
    std::vector<std::pair<std::regex, Handler>> _PUT_route;
    std::vector<std::pair<std::regex, Handler>> _DELETE_route;
};